// Το singleton "feredata" λειτουργεί κυρίως ως namespace και αφορά σε δομές και
// λειτουργίες που σχετίζονται με τη διαδικασία παραλαβής σκηνικών δεδομένων από
// τον Node server.

Prefadoros.feredata = {
	dedomena: {},

	diekopi: false,

	counter: {
		request: 0,
		error: 0,
		same: 0,
		obsolete: 0,
		apopira: 0,
		anikto: 0,
	},
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η function "ekinisi" εκκινεί τη διαδικασία παραλαβής δεδομένων από τον server
// με σκοπό την ενημέρωση του σκηνικού στον client. Αρχικά γίνεται αίτημα για
// αποστολή πλήρους σκηνικής εικόνας και ακολουθούν αιτήματα για τις μεταβολές.
// Τα δεδομένα πλήρους σκηνικής εικόνας ονομάζονται "φρέσκα", ενώ τα δεδομένα
// μεταβολών ονομάζονται "μεταβολές" ή "κινήσεις".
// Τα αιτήματα πλήρους σκηνικής εικόνας απανωνται άμεσα από τον Node sever.
// Τα αιτήματα μεταβολών απαντώνται άμα τη εμφανίσει έστω και μιας μεταβολής.
// Αυτό σημαίνεί ότι ένα αίτημα μεταβολών είναι πιθανόν να απαντηθεί άμεσα,
// εφόσον κατά την άφιξή του στον server διαπιστωθούν μεταβολές, υπάρχει όμως
// περίπτωση να τεθούν και σε αναμονή μέχρι να εμφανιστεί κάποια μεταβολή. Για
// να αποφύγουμε δυσάρεστες καταστάσεις «παγώματος» υπάρχει κάποιο timeout που
// αφορά στον μέγιστο χρόνο παραμονής αιτήματος σε κατάσταση αναμονής, π.χ. 20
// seconds. Αν δεν έχουμε μεταβολές σε αυτό το χρονικό διάστημα, το αίτημα
// επιστρέφει με κωδικοποιημένη πληροφορία που πληροφορεί τον client ότι δεν
// παρουσιάστηκαν μεταβολές για αρκετά μεγάλο χρονικό διάστημα, οπότε ο client,
// εφόσον είναι «ζωντανός», υποβάλλει νέο αίτημα κοκ.
// Τα δεδομένα είναι σε json format και περιλαμβάνουν τα properties, "t", "s",
// "p" και "l" για την πλήρη σκηνική εικόνα, ενώ για τις μεταβολές επιστρέφεται
// μόνο το property "k" με το array των μεταβολών.

Prefadoros.feredata.ekinisi = function() {
	// Πρίν αρχίσει το πάρε δώσε με τον Node server, προετοιμάζουμε το χώρο
	// προβολής στοιχείων ελέγχου της διαδικασίας. Τα στοιχεία αυτά αφορούν
	// στα αιτήματα που υποβάλλονται και στο είδος των απαντήσεων, και
	// προβάλλονται στο κάτω δεξιά μέρος τής σελίδας.

	$('#ribbonRight').append('<div id="monitor" title="Περιοχή παρακολούθησης αιτημάτων">' +
		'<div id="monitorBulletArea"></div>' +
		'<div id="monitorNumberArea"></div>' +
	'</div>');
	$('#prefadoros').fadeIn(function() {
		Prefadoros.tsoxa.setup();
	});

	// Στην όλη διαδικασία παίζει σημαντικό ρόλο η σκηνική θέση του παίκτη που
	// τρέχει το πρόγραμμα στον client. Πιο συγκεκριμένα, είναι απαραίτητο να
	// γνωρίζουμε ποιος είναι ο παίκτης αυτός, αν βρίσκεται σε κάποιο τραπέζι
	// ως παίκτης, ή ως θεατής, ή εαν είναι περιφερόμενος. Τα περισσότερα από
	// αυτά τα στοιχεία θα διαπιστωθούν αμέσως μετά την πρώτη παραλαβή δεδομένων
	// από τον Node server, αλλά πριν γίνει αυτό προετοιμάζουμε τη δομή που
	// θα περιγράφει τη σκηνική παρουσία τού παίκτη. Αυτό η δομή είναι το
	// αντικείμενο "Prefadoros.ego" και περιλαμβάνει τα εξής properties:
	//
	//	login		Το login name τού παίκτη που τρέχει το πρόγραμμα
	//			στον client.
	//
	//	pektis		Αναφορά στο σκηνικό αντικείμενο τού παίκτη.
	//
	//	sinedria	Αναφορά στο σκηνικό αντικείμενο τής συνεδρίας τού
	//			παίκτη.
	//
	// Αρχικά τίθεται το property "login" και μετά την πρώτη παραλαβή θα τεθούν
	// τα υπόλοιπα properties, τα οποία θα ενημερώνονται στην πορεία μέσω των
	// δεδομένων μεταβολών.

	Prefadoros.ego.setup();

	// Υποβάλλουμε το πρώτο μας αίτημα για παραλαβή πλήρους σκηνικής εικόνας.
	// Αυτό καθορίζεται από την παράμετρο "true".

	Prefadoros.feredata.ipovoli(true);
}

// Με την function "ipovoli" υποβάλλουμε αίτημα παραλαβής δεδομένων από τον server.
// Η παράμετρος "freska" δηλώνει αν θέλουμε ολοκληρωμένη εικόνα του σκηνικού που
// υπάρχει στον server. Αν είναι false, τότε λαμβάνουμε μόνο νέες κινήσεις, δηλαδή
// αυτές που έγιναν από το προηγούμενο σημείο ενημέρωσης και μετά.
// Η function μπορεί να δεχθεί ως δεύτερη παράμετρο και callback function, η οποία
// θα εκτελεστεί μετά την παραλαβή και τη διαχείριση των αποτελεσμάτων. Αυτή είναι
// χρήσιμο κυρίως στη «φυτευτή» υποβολή αιτημάτων μέσω της πασχαλίτσας του control
// panel και πρόκειτια για τελείως δευτερεύουσα λειτουργία που αφορά κυρίως στην
// τακτοποίηση κάποιων εικονιδίων κλπ.

Prefadoros.feredata.ipovoli = function(freska, callback) {
	// Αυξάνουμε τον συνολικό μετρητή αιτημάτων και παράλληλα αυξάνουμε τον
	// μετρητή ανοικτών αιτημάτων.

	Prefadoros.feredata.counter.request++;
	Prefadoros.feredata.counter.anikto++;

	var params = '';
	if (freska) {
		// Κατά την υποβολή αιτήματος πλήρους σκηνικής εικόνας, εμφανίζουμε
		// ενημερωτική πινακίδα σε κεντρικό σημείο τής σελίδας, μέχρι την
		// παραλαβή των σχετικών δεδομένων.

		$('#feredataLoad').anadisi().fadeIn(200);
		Client.fyi.pano('<span class="plagia">Παραλαβή δεδομένων. Παρακαλώ περιμένετε…</span>');
		params += 'freska=yes';
	}

	// Υποβάλλουμε αυτή τη στιγμή το αίτημα παραλαβής στοιχείων στον Node server.
	// Η υπηρεσία που θα απαντήσει στο αίτημά μας είναι η "feredata.poll" όπως
	// φαίνεται στο routing του υποβληθέντος αιτήματος "feredata".

	Client.node('feredata', params, function(rsp) {
		// Με την έλευση της απάντησης μειώνουμε άμεσα τον μετρητή τών
		// ανοικτών αιτημάτων.

		Prefadoros.feredata.counter.anikto--;

		// Αν επιθυμούμε να διακόψουμε την όλη διαδικασία, π.χ. λόγω λαθών,
		// μπορούμε να θέσουμε τη flag "diekopi". Σ' αυτή την περίπτωση,
		// αγνοούμε τα δεδομένα τα οποία παραλαμβάνουμε και δεν προβαίνουμε
		// σε καμία περαιτέρω ενέργεια.

		if (Prefadoros.feredata.diekopi) return;

console.log(rsp);
		// Επιχειρούμε να κατασκευάσουμε αντικείμενο με βάση τα επιστρεφόμενα
		// data που όπως προείπαμε πρέπει να είναι σε json format.

		if (!rsp) {
			Prefadoros.feredata.lathos('Δεν παρελήφθησαν δεδομένα');
		}
		else try {
			eval('Prefadoros.feredata.dedomena = {"@":1' + rsp + '};');
		} catch(e) {
			Prefadoros.feredata.lathos(rsp);
		}

		// Θα διαχειριστούμε τα δεδομένα έστω κι αν έχουν σφάλματα. Τα
		// δεδομένα θεωρούνται λανθασμένα εφόσον έχουν property "?" και η
		// τιμή του συγκεκριμένου property περιέχει μήνυμα που περιγράφει
		// το σφάλμα.
		// Αν επιστραφεί true από την function διαχείρισης, τότε δρομολογούμε
		// νέο αίτημα παραλαβής στοιχείων.

		if (Prefadoros.feredata.process(freska)) Prefadoros.feredata.kepali();
		if (callback) callback();
	});
}

// Η function "process" είναι αυτή που διαχειρίζεται σε πρώτο επίπεδο τα επιστρεφόμενα
// δεδομένα. Αφού ελέγξει την ορθότητα και το είδος των επιστρεφομένων στοιχείων, προχωρεί
// στη διαχείριση των επιμέρους στοιχείων.
// Αν η function κρίνει ότι τα επιστρεφόμενα δεδομένα δεν δικαιολογούν τη δρομολόγηση
// νέου αιτήματος, επιστρέφει false, αλλιώς επιστρέφει true.

Prefadoros.feredata.process = function(freska) {
	// Αν επιστραφεί property "~" σημαίνει ότι έχουμε δρομολογήσει νεότερο
	// αίτημα και πρόκειται για την επιστροφή από παλαιότερο αίτημα το οποίο
	// είναι συνεπώς παρωχημένο και πρέπει να αγνοηθεί και να μην δρομολογηθεί
	// νέο.

	if (Prefadoros.feredata.dedomena.hasOwnProperty('~')) {
		// Πρώτα ελέγχουμε αν πράγματι έχουμε δρομολογήσει νεότερο αίτημα,
		// καθώς υπάρχει περίπτωση να έχουμε επαναφόρτωση της σελίδας από
		// από άλλο παράθυρο του browser, ή από άλλον browser.

		if (Prefadoros.feredata.counter.anikto < 1) window.close();
		else Prefadoros.feredata.counter.update('obsolete');
		return false;
	}

	// Αν στα δεδομένα μας υπάρχει property "?" σημαίνει ότι τα δεδομένα
	// είναι λανθασμένα οπότε δρομολογούμε νέο αίτημα.

	if (Prefadoros.feredata.dedomena.hasOwnProperty('?')) {
		Client.fyi.epano(Prefadoros.feredata.dedomena['?']);
		Prefadoros.feredata.counter.update('error');
		return true;
	}

	// Αν έχει επιστραφεί property "=" σημαίνει ότι το poll έληξε χωρίς να
	// παρουσιαστεί ανάγκη επιστροφής νέων δεδομένων. Με λίγα λόγια, σημαίνει
	// ότι η κατάσταση δεν έχει αλλάξει και ο Node server έκλεισε το αίτημα
	// λόγω timeout. Και σ' αυτή την περίπτωση θα πρέπει, φυσικά, να δρομολογηθεί
	// νέο αίτημα.

	if (Prefadoros.feredata.dedomena.hasOwnProperty('=')) {
		Prefadoros.feredata.counter.update('same');
		return true;
	}

	// Αν το αίτημα αφορούσε πλήρη σκηνικά δεδομένα, θα πρέπει να υπάρχει πινακίδα
	// που μας πληροφορεί σχετικά σε κεντρικό σημείο τής σελίδας. Αυτή η πινακίδα
	// πρέπει πια να κρυφτεί.

	if (freska) {
		$('#feredataLoad').delay(1500).fadeOut(500, function() {
			Client.fyi.pano();
			Client.fyi.kato('<span class="plagia">Καλή διασκέδαση και καλές σολαρίες!</span>');
		});
		setTimeout(function() {
			Prefadoros.sizitisi.kafenioJQL.scrollKato();
			Prefadoros.sizitisi.trapeziJQL.scrollKato();
		}, 1500);
	}

	// Αν επιστραφεί property "-" σημαίνει ότι δεν βρέθηκε συνεδρία στον server,
	// επομένως θα πρέπει να γίνει επανείσοδος.

	if (Prefadoros.feredata.dedomena.hasOwnProperty('-')) {
		Prefadoros.feredata.counter.update('fatal');
		$('#exodos').edoKita();
		globals.fatal('Η συνεδρία σας έχει κλείσει και η επικοινωνία σας με τον server έχει\n' +
			'διακοπεί. Συνήθως αυτό οφείλεται σε επανείσοδο του ιδίου παίκτη στο\n' +
			'σύστημα. Όπως και να έχει είναι καλό να επιχειρήσετε έξοδο και αν δεν\n' +
			'έχετε ήδη εισέλθει από άλλον υπολογιστή επιχειρήστε επανείσοδο.');
		return false;
	}

// Κρατώ κάπου τα στοιχεία που με αφορούν πριν διαχειριστώ τα δεδομένα που
// μόλις παρέλαβα.

Prefadoros.ego.prinKeep();

	// Έχουν επιστραφεί δεδομένα και προχωρούμε στη διαχείριση των δεδομένων αυτών.
	// Τα δεδομένα αφορούν ή σε πλήρη εικόνα του σκηνικού (properties "t", "p" και "s"),
	// ή σε μεταβολές (property "k")· δεν μπορούν να περιέχουν και τις δύο κατηγορίες
	// ταυτόχρονα.

	if (freska) {
		// Όλες οι περιοχές της σελίδας που παρουσιάζουν το σκηνικό
		// έχουν ψευδοclass "feredata", ακριβώς για να μπορούμε να τα
		// «καθαρίζουμε» με μια κίνηση σ' αυτό το σημείο της παραλαβής
		// πλήρους σκηνικής εικόνας και πριν την επαναδημιουργία τών
		// σχετικών DOM elements που συνεπάγονται αυτά τα σκηνικά
		// δεδομένα.

		$('.feredata').empty();

		// Διαχειριζόμαστε τις διάφορες ενότητες των δεδομένων που έχουν
		// επιστραφεί με επιμέρους functions και δημιουργούμε με τον τρόπο
		// αυτό το σκηνικό.

		Prefadoros.feredata.pektis();
		Prefadoros.feredata.sxesi();
		Prefadoros.feredata.trapezi();
		Prefadoros.feredata.sinedria();
		Prefadoros.feredata.prosklisi();
		Prefadoros.feredata.sizitisi();

		// Έχουμε πια πλήρη σκηνική εικόνα οπότε ενημερώνουμε το αντικείμενο
		// που περιγράφει τη θέση του παίκτη που τρέχει το πρόγραμμα μέσα
		// σ' αυτό το σκηνικό και προχωρούμε στην αντανάκλαση του σκηνικού
		// στο DOM.

		Prefadoros.ego.refresh();
		Prefadoros.feredata.stisimoSkinikoDOM();
		Prefadoros.feredata.metenergia();
		Client.sound.play('tap.ogg');
	}
	else {
		// Είμαστε στην περίπτωση τής παραλαβής δεδομένων μεταβολών και
		// θα πρέπει να διαχειριστούμε μια προς μια όλες τις μεταβολές
		// με σκοπό να επικαιροποιήσουμε το σκηνικό μας. Για κάθε είδος
		// κινήσεως καλείται ιδιαίτερη function διαχείρισης, κάτι σαν
		// τους device drivers των λειτουργικών συστημάτων.

		Prefadoros.feredata.kinisi(freska);
	}

	Prefadoros.cpanel.omadaDixe();
	Prefadoros.tsoxa.panelDixe();
	Prefadoros.feredata.counter.update('normal', freska);
	return true;
}

Prefadoros.feredata.kepali = function() {
	var t = 100, freska;

	if (Prefadoros.feredata.dedomena.hasOwnProperty('?')) {
		Prefadoros.feredata.counter.apopira++;
		$('#feredataInfo').append('&#9632;');

		if (Prefadoros.feredata.counter.apopira > 9) {
			Prefadoros.feredata.counter.update('fatal');
			Prefadoros.feredata.diekopi = true;
			$('#feredataLoad').fadeOut(function() { $(this).remove(); });
			globals.fatal('Δεν παρελήφθησαν δεδομένα. Ανανεώστε τη\n' +
				'σελίδα ή επιχειρήστε έξοδο και επανείσοδο.');
		}

		if (Prefadoros.feredata.counter.apopira > 6) t = 400;
		else if (Prefadoros.feredata.counter.apopira > 3) t = 200;

		// Αν το σφάλμα οφείλεται σε διακοπή και επαναλειτουργία του server
		// πρέπει να γίνει εξαρχής ενημέρωση του σκηνικού λόγω της διαγραφής
		// των "feredata" ids.

		freska = true;
	}
	else {
		$('#feredataInfo').empty();
		Prefadoros.feredata.counter.apopira = 0;
		freska = false;
	}

	setTimeout(function() {
		Prefadoros.feredata.ipovoli(freska);
	}, t);
}

Prefadoros.feredata.lathos = function(s) {
	Prefadoros.feredata.dedomena = {
		'?': s
	};
}

// Η function "counter.update" καλείται αμέσως μετά την επιστροφή δεδομένων από
// τον server και σκοπό έχει την εμφάνιση στοιχείων της συγκεκριμένης παραλαβής
// στο κάτω δεξιά μέρος της σελίδας. Πράγματι εκεί εμφανίζεται το πλήθος των
// αιτημάτων που έγιναν στο συγκεκριμένο session καθώς επίσης και μια βούλα
// για κάθε παραλαβή. Οι βούλες φέρουν συγκεκριμένο χρώμα ανάλογα για το αν
// πρόκειται για παραλαβή νέων στοιχείων, για timeout, για λανθασμένα στοιχεία,
// ή για παρωχημένα στοιχεία.
//
// Ως παράμετρο περνάμε τα strings "error", "same", ή "obsolete" ανάλογα με
// το αν πρόκειται για λανθασμένα, αναλλοίωτα, ή παρωχημένα στοιχεία. Αν δεν
// περάσουμε παράμετρο τότε θεωρούμε ότι παρελήφθησαν νέα δεδομένα τα οποία
// θα προκαλέσουν κάποια αλλαγή στο σκηνικό του client.

Prefadoros.feredata.counter.update = function(reso, freska) {
	var bullet, html, title;

	bullet = freska ?
		9632	// solid square
	:
		9679;	// solid bullet

	switch (reso) {
	case 'normal':		// έχει ήδη καταμετρηθεί ως request
		break;
	case 'fatal':		// σφάλμα, απλώς αλλάζω το bullet
		reso = 'error';
		bullet = 9632;
	default:
		Prefadoros.feredata.counter[reso]++;
	}

	html = '<span id="monitorRequest" title="Συνολικό πλήθος αιτημάτων συνεδρίας">' +
		Prefadoros.feredata.counter.request + '</span>';
	if (Prefadoros.feredata.counter.error)
		html += ' # <span id="monitorError" title="Πλήθος αποτυχημένων αιτημάτων συνεδρίας">' +
			Prefadoros.feredata.counter.error + '</span>';
	$('#monitorNumberArea').html(html);

	if (Prefadoros.feredata.counter.request >= 20) {
		$('#monitorBulletArea span').last().remove();
		$('#monitorBulletArea span').last().html('&hellip;');
	}
	
	switch (reso) {
	case 'normal':
		title = freska ? 'Επεστράφησαν πλήρη σκηνικά δεδομένα' : 'Επεστράφησαν δεδομένα';
		break;
	case 'error':
		title = 'Επεστράφησαν λανθασμένα δεδομένα';
		break;
	case 'same':
		title = 'Ανανέωση αιτήματος, δεν παρουσιάστηκαν μεταβολές';
		break;
	case 'obsolete':
		title = 'Παρωχημένο αίτημα';
		break;
	default:
		title = '';
		break;
	}

	$('#monitorBulletArea').prepend('<span class="monitorBullet' + reso + '" title="' +
		title + '">&#' + bullet + ';</span>');
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η function "pektis" διαχειρίζεται δεδομένα που αφορούν στους παίκτες τού
// σκηνικού.
// Η function εισάγει τους παίκτες στο σκηνικό του client. Οι παίκτες δεν έχουν
// άμεση σχέση με το DOM, με την έννοια ότι δεν εμφανίζονται κάπου αυτόνομα,
// απλώς τα στοιχεία των παικτών είναι απαραίτητα σε στοιχεία που εισάγονται
// στο DOM, όπως είναι οι περιφερόμενοι, οι νιόφερτοι, οι θεατές και οι παίκτες
// των τραπεζιών.

Prefadoros.feredata.pektis = function() {
	Skiniko.pektis = {};
	if (!Prefadoros.feredata.dedomena.hasOwnProperty('p')) return;
	globals.walk(Prefadoros.feredata.dedomena.p, function(login, pektis) {
		(new Pektis()).feredataSet(login, pektis).pektisAdd();
	});
}

Prefadoros.feredata.sxesi = function() {
	if (!Prefadoros.feredata.dedomena.hasOwnProperty('x')) return;
	globals.walk(Prefadoros.feredata.dedomena.x, function(sxetizomenos, sxesi) {
		(new Sxesi()).feredataSet(sxetizomenos, sxesi).sxesiAdd();
	});
}

// Η function "trapezi" διαχειρίζεται επιστρεφόμενα δεδομένα που αφορούν
// στα τραπέζια τού σκηνικού. Η function εισάγει τα τραπέζια στο σκηνικό
// του client, αλλά δεν τα εισάγει στο DOM.

Prefadoros.feredata.trapezi = function() {
	var i;

	Skiniko.trapezi = {};
	if (!Prefadoros.feredata.dedomena.hasOwnProperty('t')) return;
	for (i = 0; i < Prefadoros.feredata.dedomena.t.length; i++) {
		(new Trapezi()).feredataSet(Prefadoros.feredata.dedomena.t[i]).trapeziAdd();
	}
}

// Η function "sinedria" διαχειρίζεται δεδομένα που αφορούν στις συνεδρίες
// τού σκηνικού. Οι συνεδρίες εντάσσονται στο σκηνικό, αλλά προς το παρόν
// δεν αντανακλούν στο DOM.

Prefadoros.feredata.sinedria = function() {
	var i;

	Skiniko.sinedria = {};
	if (!Prefadoros.feredata.dedomena.hasOwnProperty('s')) return;
	for (i = 0; i < Prefadoros.feredata.dedomena.s.length; i++) {
		(new Sinedria()).feredataSet(Prefadoros.feredata.dedomena.s[i]).sinedriaAdd();
	}
}

// Η function "prosklisi" διαχειρίζεται δεδομένα που αφορούν στις προσκλήσεις
// τού σκηνικού.

Prefadoros.feredata.prosklisi = function() {
	var i;

	Skiniko.prosklisi = {};
	if (!Prefadoros.feredata.dedomena.hasOwnProperty('l')) return;
	for (i = 0; i < Prefadoros.feredata.dedomena.l.length; i++) {
		(new Prosklisi()).feredataSet(Prefadoros.feredata.dedomena.l[i]).prosklisiAdd();
	}
}

// Η function "sizitisi" διαχειρίζεται δεδομένα που αφορούν στη συζήτηση
// του καφενείου.

Prefadoros.feredata.sizitisi = function() {
	var i;

	if (!Prefadoros.feredata.dedomena.hasOwnProperty('z')) return;
	for (i = 0; i < Prefadoros.feredata.dedomena.z.length; i++) {
		Prefadoros.sizitisi.kafenioJQL.
		sizitisiAdd((new Sizitisi()).feredataSet(Prefadoros.feredata.dedomena.z[i]));
	}
}

// Η function "energia" διαχειρίζεται δεδομένα που αφορούν στις ενέργειες
// της τελευταίας διανομής του τραπεζιού του χρήστη.

Prefadoros.feredata.energia = function() {
	var trapezi = Prefadoros.ego.trapezi;
	if (trapezi) trapezi.energiaSet(Prefadoros.feredata.dedomena['E']);
}

// Η function "kinisi" διαχειρίζεται δεδομένα μεταβολών.

Prefadoros.feredata.kinisi = function() {
	var i, kinisi;

	if (!Prefadoros.feredata.dedomena.hasOwnProperty('k')) return;
	for (i = 0; i < Prefadoros.feredata.dedomena.k.length; i++) {
		kinisi = new Kinisi(Prefadoros.feredata.dedomena.k[i]);
		if (!kinisi.hasOwnProperty('?')) globals.fatal('Ακαθόριστο είδος κίνησης');
		if (!Prefadoros.feredata.kinisiMap.
			hasOwnProperty(kinisi['?'])) globals.fatal(kinisi['?'] + ': άγνωστο είδος κίνησης');
		Prefadoros.feredata.kinisiMap[kinisi['?']](kinisi);
	}
}

Prefadoros.feredata.kinisiMap = {
	//	SN	Νέα συνεδρία (είσοδος παίκτη).
	//
	//	p	Το login name του παίκτη.
	//
	//	o	Το όνομα του παίκτη.
	//
	//	r	Λίστα παραμέτρων του παίκτη σε οικονομική μορφή.

	'SN':	function(kinisi) {
		(new Sinedria()).kinisiSet(kinisi).entopismos().sinedriaAdd().sinedriaAddDOM();
	},

	//	NS	Τέλος συνεδρίας (έξοδος παίκτη).
	//
	//	p	Το login name του παίκτη.

	'NS':	function(kinisi) {
		var sinedria, trapezi;

		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p'));
		sinedria.sinedriaDel().sinedriaDelDOM();

		if (sinedria.oxiPektis()) return;

		trapezi = Skiniko.isTrapezi(sinedria.trapezi);
		if (!trapezi) return;

		if (trapezi.oxiEgo()) return;
	},

	'PPRM':	function(kinisi) {
		var
		pektis = Skiniko.fetchPektis(kinisi.fetchProp('p')),
		param = Prefadoros.peparamOce(kinisi.fetchProp('r')),
		timi = Prefadoros.peparamDecode(param, kinisi.fetchProp('t'));

		pektis.peparamSet(param, timi);
		switch (param) {
		case 'ΚΑΤΑΣΤΑΣΗ':
			pektis.pektisBoxJQL({ola:1}).pektisKatastasiFixDOM(kinisi.p);
			break;
		case 'ΑΞΙΩΜΑ':
			pektis.pektisBoxJQL({ola:1}).pektisAxiomaFixDOM(kinisi.p);
			break;
		}
	},

	'PR': function(kinisi) {
		(new Pektis()).feredataSet(kinisi.fetchProp('p'), kinisi).pektisAdd().pektisFixDOM();
	},

	// NT -- Νέο τραπέζι
	// -----------------
	// Η κίνηση νέου τραπεζιού αφορά σε νέο τραπέζι που δηιουργεί κάποιος
	// παίκτης και πρέπει να φέρει τα εξής properties:
	//
	//	p	Το login name του παίκτη που δημιουργεί το τραπέζι.
	//
	//	t	Ο κωδικός του νέου τραπεζιού.
	//
	//	l	Ο κωδικός της πρόσκλησης του δημιουργού προς τον
	//		εαυτό του (αυτοπρόσκληση).

	'NT': function(kinisi) {
		var sinedria, trapezi, prosklisi, scrl, prin;

		// Εντάσσουμε το τραπέζι στο σκηνικό του client.

		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p'));
		prin = (new Sinedria()).sinedriaThesiCopy(sinedria);
		trapezi = Trapezi.trapeziNeo(kinisi.fetchProp('t'), sinedria.pektis, kinisi.fetchProp('l'));

		// Ενημερώνουμε τα στοιχεία θέσης μας (μπορεί να είμαστε εμείς που δημιουργήσαμε
		// το τραπέζι) και προχωρούμε στην ένταξη του τραπεζιού και τής αυτοπρόσκλησης
		// στο DOM.

		Prefadoros.ego.refresh();
		trapezi.trapeziAddDOM(true);
		Skiniko.fetchProsklisi(kinisi.l).prosklisiAddDOM(true);
		sinedria.alagiThesisFixDOM(prin);

		// Το τραπέζι έχει ήδη ενταχθεί στο σκηνικό και στο DOM του καφενείου.
		// Αυτό που μένει είναι να ενημερωθεί το DOM όσον αφορά στην παρτίδα,
		// αλλά αυτό είναι κάτι που θα γίνει μόνον εφόσον το τραπέζι μας αφορά.

		if (trapezi.oxiEgo()) {
			if (Prefadoros.optiki.isKafenio()) Client.sound.trapeziNeo();
			return;
		}

		Trapezi.refresh();
		$('.trapeziDataEgo').removeClass('trapeziDataEgo');
		trapezi.trapeziJQL().find('.trapeziData').addClass('trapeziDataEgo').dataFlush();

		$('#kafenio').scrollTop(0);
		scrl = parseInt($('#trapeziArea').offset().top - $('#kafenio').offset().top) - 100;
		if (scrl < 0) scrl = 0;
		$('#kafenio').scrollTop(scrl);

		Prefadoros.sizitisi.trapeziJQL.empty();
		Prefadoros.optiki.partida();
		Client.sound.trapeziNeo();
	},

	'NL':	function(kinisi) {
		var prosklisi, ixos;

		prosklisi = (new Prosklisi()).kinisiSet(kinisi).prosklisiAdd().prosklisiAddDOM(true);
		if (prosklisi.apo.isEgo()) ixos = 'klak.ogg';
		else if (Prefadoros.ego.pektis.isFilos(prosklisi.apo)) ixos = 'sfirigma.ogg';
		else ixos = 'pap.ogg';
		Client.sound.play(ixos);
		if (prosklisi.pros.isEgo()) prosklisi.prosklisiTrapeziFixDOM();
	},

	'LN':	function(kinisi) {
		var prosklisi = Skiniko.fetchProsklisi(kinisi.fetchProp('k')).prosklisiDel().prosklisiDelDOM();
		Client.sound.play(prosklisi.apo.isEgo() ? 'tsalakoma.ogg' : 'skisimo.ogg');
		if (prosklisi.pros.isEgo()) prosklisi.prosklisiTrapeziFixDOM();
	},

	// AP -- Αποδοχή πρόσκλησης
	// ------------------------
	// Η κίνηση αποδοχής πρόσκλησης αφορά σε αποδοχή πρόσκλησης από κάποιον παίκτη
	// και αποστέλλεται σε όλους τους clients, καθώς αλλάζει την εικόνα τού καφενείου.
	// Η κίνηση μεταφέρει τα παρακάτω properties:
	//
	//	p	Το login name τού παίκτη που αποδέχεται την πρόσκληση.
	//
	//	t	Ο κωδικός τραπεζιού στο οποίο αφορά η πρόσκληση.

	'AP':	function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = Skiniko.fetchTrapezi(kinisi.fetchProp('t')),
		sinedriaPrin, sinedriaMeta, ixos;

		sinedriaPrin = (new Sinedria()).sinedriaThesiCopy(sinedria);
		trapeziPrin = (new Trapezi()).trapeziThesiCopy(trapezi);
		sinedria.apodoxiProsklisis(trapezi, kinisi.fetchProp('h'));
		sinedriaMeta = (new Sinedria()).sinedriaThesiCopy(sinedria);
		Prefadoros.ego.refresh();

		sinedria.alagiThesisFixDOM(sinedriaPrin, sinedriaMeta);
		ixos = sinedria.bikePektisAlarm(trapeziPrin);
		if (sinedria.isEgo()) Trapezi.refresh(!ixos);
	},

	//	IS	Είσοδος σε τραπέζι.
	//
	//	p	Ο παίκτης που εισέρχεται στο τραπέζι.
	//
	//	t	Το τραπέζι στο οποίο εισέρχεται.

	'IS':	function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = Skiniko.fetchTrapezi(kinisi.fetchProp('t')),
		sinedriaPrin, sinedriaMeta;

		sinedriaPrin = (new Sinedria()).sinedriaThesiCopy(sinedria);
		sinedria.trapeziIsodos(trapezi);
		sinedriaMeta = (new Sinedria()).sinedriaThesiCopy(sinedria);
		Prefadoros.ego.refresh();

		sinedria.alagiThesisFixDOM(sinedriaPrin);
		if (sinedria.isEgo()) Trapezi.refresh();
	},

	//	EX	Έξοδος από τραπέζι.
	//
	//	p	Ο παίκτης που εξέρχεται από το τραπέζι.

	'EX':	function(kinisi) {
		var trapezi, login, s, ixos = false,
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		sinedriaPrin = {},	// λίστα συνεδριών θέσης πριν την έξοδο
		sinedriaMeta = {},	// λίστα συνεδριών θέσης μετά την έξοδο
		plist = {},		// λίστα συνεδριών που σχετίζονται με το τραπέζι
		llist = {};		// λίστα προσκλήσεων τού τραπεζιού

		trapezi= Skiniko.fetchTrapezi(sinedria.fetchProp('trapezi'));

		// Αν ο παίκτης που εξέρχεται είναι παίκτης του τραπεζιού, τότε υπάρχει
		// περίπτωση η έξοδος αυτή να προκαλέσει αρχειοθέτηση τού τραπεζιού,
		// επομένως είναι καλό να κρατήσουμε τις προσκλήσεις και τις σχετικές
		// συνεδρίες.

		if (sinedria.isPektis()) {
			Trapezi.trapeziThesiJQL(sinedria.trapezi, sinedria.thesi).find('.pektisOnoma').remove();
			plist = trapezi.plist();
			llist = trapezi.llist();
		}

		// Αλλιώς πρόκειται για θεατή και θα είναι ο μόνος που θα επηρεαστεί από
		// την έξοδό του από το τραπέζι.

		else {
			plist[sinedria.pektis] = null;
		}

		// Κρατάμε κάπου τα στοιχεία θέσης των συνεδριών που εμπλέκονται με το
		// τραπέζι, επαναδιμορφώνοντας παράλληλα τη λίστα των εμπλεκομένων
		// συνεδριών.

		for (login in plist) {
			s = Skiniko.isSinedria(login);
			if (s) sinedriaPrin[login] = (new Sinedria()).sinedriaThesiCopy(s);
			else delete plist[login];
		}

		// Επιτελούμε την έξοδο του παίκτη από το τραπέζι. Αν αυτό προκαλέσει
		// αρχειοθέτηση του τραπεζιού, θα μας επιστρεφεί λίστα συνεδριών που
		// επανεντοπίστηκαν από τη διαδικασία τής αρχειοθέτησης, αλλιώς η λίστα
		// θα περιλαμβάνει μόνο τον εξερχόμενο παίκτη.

		plist = sinedria.trapeziExodos();

		// Κρατάμε κάπου τα στοιχεία θέσης των εμπλεκομένων συνεδριών όπως
		// αυτά διαμορφώθηκαν μετά έξοδο του παίκτη από το τραπέζι, ενώ
		// παράλληλα επαναδιαμορφώνουμε τη λίστα των εμπλεκομένων συνεδριών.

		for (login in plist) {
			s = Skiniko.isSinedria(login);
			if (s) sinedriaMeta[login] = (new Sinedria()).sinedriaThesiCopy(s);
			else delete plist[login];
		}

		Prefadoros.ego.refresh();

		for (login in plist) {
			Skiniko.fetchSinedria(login).alagiThesisFixDOM(sinedriaPrin[login], sinedriaMeta[login]);
		}

		if (Skiniko.isTrapezi(trapezi.kodikos)) ixos = sinedriaPrin[sinedria.pektis].bgikePektisAlarm();
		else trapezi.trapeziDelDOM().trapeziProsklisiDelDOM(llist);

		if (Skiniko.oxiTrapezi(trapezi.kodikos)) {
			Client.sound.trapeziDel();
			ixos = true;
		}
		if (sinedria.isEgo()) Trapezi.refresh(!ixos);
	},

	//	P2H	Από παίκτης θεατής.
	//
	//	p	Ο παίκτης που αλλάζει ρόλο.

	'P2H':	function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi, sinedriaPrin, sinedriaMeta;

		trapezi = Skiniko.fetchTrapezi(sinedria.trapezi),
		sinedriaPrin = (new Sinedria()).sinedriaThesiCopy(sinedria);
		sinedria.pektisTheatis();
		sinedriaMeta = (new Sinedria()).sinedriaThesiCopy(sinedria);
		Prefadoros.ego.refresh();

		sinedria.alagiThesisFixDOM(sinedriaPrin, sinedriaMeta);
		sinedriaPrin.bgikePektisAlarm(sinedria);
		if (sinedria.oxiEgo()) return;

		trapezi.tsoxaDOM().xartosiaDOM();
		Prefadoros.optiki.partida();
	},

	//	H2P	Από θεατής παίκτης.
	//
	//	p	Ο παίκτης που αλλάζει ρόλο.

	'H2P':	function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		thesi = kinisi.fetchProp('h'),
		trapezi, sinedriaPrin, trapeziPrin, sinedriaMeta;

		trapezi = Skiniko.fetchTrapezi(sinedria.trapezi);
		trapeziPrin = (new Trapezi()).trapeziThesiCopy(trapezi);
		sinedriaPrin = (new Sinedria()).sinedriaThesiCopy(sinedria);
		sinedria.theatisPektis(thesi);
		sinedriaMeta = (new Sinedria()).sinedriaThesiCopy(sinedria);
		Prefadoros.ego.refresh();

		sinedria.alagiThesisFixDOM(sinedriaPrin, sinedriaMeta);
		sinedria.bikePektisAlarm(trapeziPrin);
		if (sinedria.oxiEgo()) return;

		trapezi.tsoxaDOM().xartosiaDOM();
		Prefadoros.optiki.partida();
	},

	//	HH	Αλλαγή θέσης θέασης.
	//
	//	p	Ο θεατής που αλλάζει θέση.
	//
	//	h	Η νέα θέση θέασης.

	'HH':	function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		sinedriaPrin, sinedriaMeta;

		sinedriaPrin = (new Sinedria()).sinedriaThesiCopy(sinedria);
		sinedria.thesiTheasis(kinisi.fetchProp('h'));
		sinedriaMeta = (new Sinedria()).sinedriaThesiCopy(sinedria);
		Prefadoros.ego.refresh();
		sinedria.alagiThesisFixDOM(sinedriaPrin, sinedriaMeta);
		if (sinedria.oxiEgo()) return;

		Prefadoros.ego.trapezi.xartosiaDOM().energiaDOM();
		Prefadoros.feredata.metenergia();
		Client.sound.thesiTheasis();
	},

	'SX':	function(kinisi) {
		(new Sxesi()).kinisiSet(kinisi).sxesiAdd();
		Pektis.pektisBoxJQL(kinisi.l, {ola:1}).pektisSxesiFixDOM(kinisi.l);
		Pektis.prosklisiJQL(kinisi.l).prosklisiSxesiFixDOM(kinisi.l);
		Pektis.anazitisiJQL(kinisi.l).anazitisiSxesiFixDOM(kinisi.l);
		Pektis.profinfoJQL(kinisi.l).profinfoSxesiFixDOM(kinisi.l);
	},

	'RLI': function(kinisi) {
		var tok, thesi,
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi();

		tok = Prefadoros.stisimo.roloiPrep(trapezi, sinedria);
		Prefadoros.stisimo.roloi(trapezi, tok);
		trapezi.trapeziPektisFixDOM();
		trapezi.stisimoIdioktitoFixDOM();
		trapezi.stisimoEndixi(sinedria, 'Κυκλική εναλλαγή παικτών', 'cpanel/roloi.png');
	},

	'DTX': function(kinisi) {
		var tok, thesi,
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi();

		tok = Prefadoros.stisimo.diataxiPrep(trapezi, sinedria);
		if (!tok) return;

		Prefadoros.stisimo.diataxi(trapezi, tok);
		for (thesi in Prefadoros.thesiValid) {
			trapezi.trapeziPektisFixDOM(thesi);
		}
		trapezi.stisimoEndixi(sinedria, 'Αλλαγή διάταξης παικτών', 'cpanel/diataxi.png');
	},

	'KAS': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.kasaPrep(trapezi, sinedria);
		Prefadoros.stisimo.kasa(trapezi, tok);
		trapezi.apodoxiFixDOM().trapeziDataFixDOM();
		trapezi.stisimoEndixi(sinedria, 'Αλλαγή κάσας σε ' + trapezi.kasa(), 'cpanel/kasa.png');
	},

	'K+': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = Skiniko.fetchTrapezi(kinisi.fetchProp('t')),
		kasa = kinisi.fetchProp('k');

		trapezi.trparam['ΚΑΣΑ'] = kasa;
		trapezi.
		trapeziDataFixDOM().
		tsoxaDataPanoFixDOM().
		stisimoEndixi(sinedria, 'Αύξηση κάσας σε ' + trapezi.kasa(), 'velaki/kasaPano.png');
	},

	'K-': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = Skiniko.fetchTrapezi(kinisi.fetchProp('t')),
		kasa = kinisi.fetchProp('k');

		trapezi.trparam['ΚΑΣΑ'] = kasa;
		trapezi.
		trapeziDataFixDOM().
		tsoxaDataPanoFixDOM().
		stisimoEndixi(sinedria, 'Μείωση κάσας σε ' + trapezi.kasa(), 'velaki/kasaKato.png');
	},

	'PPP': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.pasoPrep(trapezi, sinedria);
		Prefadoros.stisimo.paso(trapezi, tok);
		trapezi.apodoxiFixDOM().stisimoPasoFixDOM();
		if (tok.paso) trapezi.stisimoEndixi(sinedria, 'Παίζονται οι άσοι', 'cpanel/pasoOn.png');
		else trapezi.stisimoEndixi(sinedria, 'Δεν παίζονται οι άσοι', 'cpanel/pasoOff.png');
	},

	'ACE': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.asoiPrep(trapezi, sinedria);
		Prefadoros.stisimo.asoi(trapezi, tok);
		trapezi.apodoxiFixDOM().stisimoAsoiFixDOM();
		if (tok.asoi) trapezi.stisimoEndixi(sinedria, 'Παίζονται οι άσοι', 'cpanel/asoiOn.png');
		else trapezi.stisimoEndixi(sinedria, 'Δεν παίζονται οι άσοι', 'cpanel/asoiOff.png');
	},

	'LRN': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.filikiPrep(trapezi, sinedria);
		Prefadoros.stisimo.filiki(trapezi, tok);
		trapezi.apodoxiFixDOM().stisimoFilikiFixDOM();
		if (tok.filiki) trapezi.stisimoEndixi(sinedria, 'Φιλική παρτίδα', 'cpanel/filiki.png');
		else trapezi.stisimoEndixi(sinedria, 'Αγωνιστική παρτίδα', 'cpanel/agonistiki.png');
	},

	'PTL': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.postelPrep(trapezi, sinedria);
		Prefadoros.stisimo.postel(trapezi, tok);
		trapezi.apodoxiFixDOM().stisimoPostelFixDOM();
		trapezi.stisimoEndixi(sinedria, tok.desc + ' πληρωμή τελευταίας διανομής',
			'cpanel/postel/' + tok.img + '.png');
	},

	'IDK': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.idioktitoPrep(trapezi, sinedria);
		Prefadoros.stisimo.idioktito(trapezi, tok);
		trapezi.stisimoIdioktitoFixDOM();
		if (tok.idioktito) trapezi.stisimoEndixi(sinedria, 'Ιδιόκτητο τραπέζι', 'cpanel/idioktito.png');
		else trapezi.stisimoEndixi(sinedria, 'Ελεύθερο τραπέζι', 'cpanel/elefthero.png');
	},

	'PRV': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.idiotikotitaPrep(trapezi);
		Prefadoros.stisimo.idiotikotita(trapezi, tok);
		trapezi.idiotikotitaFixDOM();
		trapezi.stisimoPriveFixDOM();
		trapezi.trapeziDataFixDOM();
		if (tok.prive) trapezi.stisimoEndixi(sinedria, 'Πριβέ τραπέζι', 'cpanel/prive.png');
		else trapezi.stisimoEndixi(sinedria, 'Δημόσιο τραπέζι', 'cpanel/dimosio.png');
	},

	'KLT': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.klistoPrep(trapezi);
		Prefadoros.stisimo.klisto(trapezi, tok);
		trapezi.stisimoKlistoFixDOM();
		if (tok.klisto) trapezi.stisimoEndixi(sinedria, 'Κλειστά φύλλα στους θεατές', 'cpanel/klisto.png');
		else trapezi.stisimoEndixi(sinedria, 'Φανερά τα φύλλα στους θεατές', 'cpanel/anikto.png');
	},

	'EPT': function(kinisi) {
		var
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p')),
		trapezi = sinedria.fetchTrapezi(),
		tok;

		tok = Prefadoros.stisimo.epetiakiPrep(trapezi);
		Prefadoros.stisimo.epetiaki(trapezi, tok);
		trapezi.stisimoEpetiakiFixDOM();
		if (tok.epetiaki) trapezi.stisimoEndixi(sinedria, 'Επετειακή παρτίδα', 'cpanel/balonia.png');
		else trapezi.stisimoEndixi(sinedria, 'Καθημερινή παρτίδα', 'cpanel/ainolab.png');
	},

	'APD': function(kinisi) {
		var sinedria, trapezi;
		sinedria = Skiniko.fetchSinedria(kinisi.fetchProp('p'));
		trapezi = sinedria.fetchTrapezi();

		Prefadoros.stisimo.apodoxi(trapezi, sinedria);
		trapezi.apodoxiFixDOM(sinedria.thesi);
		if (trapezi.apodoxi(sinedria.thesi)) trapezi.stisimoEndixi(sinedria, 'Αποδοχή όρων', 'cpanel/apodoxi.png');
		else trapezi.stisimoEndixi(sinedria, 'Επαναδιαπραγμάτευση όρων', 'cpanel/ixodopa.png');
	},

	//	MV	Ένδειξη γραφής σχολίου από κάποιον παίκτη.
	//
	//	p	Ο παίκτης που γράφει το σχόλιο.
	//
	//	t	Ο κωδικός τραπεζιού στο οποίο ο παίκτης εκκίνησε τη γραφή σχολίου.
	//		Αν δεν καθοριστεί σημαίνει ότι η γραφή εκκίνησε στο καφενείο.

	'MV': function(kinisi) {
		var login, trapezi, sxolio;

		login = kinisi.fetchProp('p');
		trapezi = kinisi.isProp('t') ? Skiniko.isTrapezi(kinisi.fetchProp('t')) : null;

		sxolio = new Sizitisi({
			'pektis': login,
			'kimeno': trapezi ? Prefadoros.sxolioKodikos.moliviTrapezi :
				Prefadoros.sxolioKodikos.moliviKafenio,
		});

		if (trapezi) Prefadoros.sizitisi.trapeziJQL.sizitisiAdd(sxolio);
		else Prefadoros.sizitisi.kafenioJQL.sizitisiAdd(sxolio);
	},

	//	VM	Ακύρωση ένδειξης γραφής σχολίου από κάποιον παίκτη.
	//
	//	p	Ο παίκτης που φαινόταν να γράφει.

	'VM': function(kinisi) {
		Prefadoros.sizitisi.moliviClear(kinisi.fetchProp('p'));
	},

	//	SZ	Σχόλιο συζήτησης.
	//
	//	p	Ο παίκτης που γράφει το σχόλιο.
	//
	//	t	Ο κωδικός τραπεζιού στο οποίο ο παίκτης βρίσκεται τη στιγμή
	//		που κάνει την αποστολή (πατάει το Enter). Αν δεν καθοριστεί
	//		τραπέζι, το σχόλιο θα προστεθεί στη συζήτηση του καφενείου.

	'SZ': function(kinisi) {
		var trapezi, sxolio;

		Prefadoros.sizitisi.moliviClear(kinisi.fetchProp('p'));
		if (kinisi.isProp('t')) {
			trapezi = Skiniko.isTrapezi(kinisi.fetchProp('t'));
			if (!trapezi) return;
		}
		else trapezi = null;

		sxolio = new Sizitisi({
			'pektis': kinisi.p,
			'kimeno': kinisi.fetchProp('k'),
			'pote': 0,
		});

		if (trapezi) Prefadoros.sizitisi.trapeziJQL.sizitisiAdd(sxolio);
		else Prefadoros.sizitisi.kafenioJQL.sizitisiAdd(sxolio);
	},

	//	DZ	Διαγραφή συζήτησης.
	//
	//	p	Ο παίκτης που διαγράφει το σχόλιο.
	//
	//	t	Ο κωδικός τραπεζιού.
	//
	//	a	Αν υπάρχει σημαίνει καθολική διαγραφή.

	'DZ': function(kinisi) {
		var trapezi, sizitisi, i, jql;

		if (Prefadoros.ego.oxiTrapezi()) return;
		if (Prefadoros.ego.sinedria.trapezi != kinisi.fetchProp('t')) return;

		trapezi = Skiniko.isTrapezi(kinisi.t);
		if (!trapezi) return;

		if (kinisi.hasOwnProperty('a')) {
			trapezi.sizitisiDiagrafi(true);
			Prefadoros.sizitisi.trapeziJQL.empty();
			Client.sound.skisimo(Client.sound.entasi['ΔΥΝΑΤΗ']);
			return;
		}

		trapezi.sizitisiDiagrafi();

		Prefadoros.sizitisi.trapeziJQL.find('.sizitisiSxolio').
			not('.sizitisiProepiskopisi').
			not('.sizitisiMolivi').
			last().remove();
			Client.sound.skisimo(Client.sound.entasi['ΧΑΜΗΛΗ']);
	},

	//	DN	Διανομή.
	//
	//	t	Ο κωδικός τραπεζιού.
	//
	//	d	Ο κωδικός διανομής.
	//
	//	l	Η θέση του dealer.

	'DN': function(kinisi) {
		var trapezi = Skiniko.isTrapezi(kinisi.fetchProp('t'));

		trapezi.dianomiAdd(new Dianomi({
			'kodikos': kinisi.fetchProp('d'),
			'dealer': kinisi.fetchProp('l'),
		}));

		if (trapezi.oxiEgo()) return;
		trapezi.tsoxaPexnidiDOM();
		Client.sound.dianomi();
	},

	//	EG	Ενέργεια.
	//
	//	t	Ο κωδικός τραπεζιού.
	//
	//	i	Το είδος της ενέργειας σε οικονομική μορφή.
	//
	//	p	Η θέση του παίκτη που εκετελεί την ενέργεια.
	//
	//	d	Τα δεδομένα τής ενέργειας.

	'EG': function(kinisi) {
		var trapezi, energia;

		trapezi = Skiniko.fetchTrapezi(kinisi.fetchProp('t'));
		energia = new Energia({
			'idos': Prefadoros.energiaIdosOce(kinisi.fetchProp('i')),
			'pektis': kinisi.fetchProp('p'),
			'data': kinisi.fetchProp('d'),
		});

		trapezi.energiaAdd(energia);
		if (trapezi.isEgo()) trapezi.energiaDOM(energia);
		Prefadoros.feredata.metenergia();
	},
};

Prefadoros.stisimo.check = function(kinisi, callback) {
	if (!kinisi.hasOwnProperty('p')) return;
	var sinedria = Sinedria.iparxi(kinisi.p);
	if (!sinedria) return;

	var trapezi = Trapezi.iparxi(sinedria.t);
	if (!trapezi) return;

	if (callback) callback(kinisi, sinedria, trapezi);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η function "stisimoSkinikoDOM" είναι αυτή που διαβάζει την πλήρη σκηνική εικόνα
// και δημιουργεί εκ του μηδενός τα αντίστοιχα DOM elements, παριστώντας ουσιαστικά
// το σκηνικό στη σελίδα τού browser.
// Ο μόνος λόγος που ανατρέχουμε πάλι στα επιστρεφόμενα δεδομένα και δεν διατρέχουμε
// πια απευθείας τα σκηνικά δεδομένα είναι η σειρά, η οποία δεν τηρείται στη σκηνική
// εικόνα, αλλά υπήρχε στα επιστρεφόμενα δεδομένα.

Prefadoros.feredata.stisimoSkinikoDOM = function() {
	var i;

	if (Prefadoros.feredata.dedomena.hasOwnProperty('t')) {
		for (i = 0; i < Prefadoros.feredata.dedomena.t.length; i++) {
			Skiniko.fetchTrapezi(Prefadoros.feredata.dedomena.t[i].k).trapeziAddDOM();
		}
	}

	if (Prefadoros.feredata.dedomena.hasOwnProperty('s')) {
		for (i = 0; i < Prefadoros.feredata.dedomena.s.length; i++) {
			Skiniko.isSinedria(Prefadoros.feredata.dedomena.s[i].p).sinedriaAddDOM();
		}
	}

	if (Prefadoros.feredata.dedomena.hasOwnProperty('l')) {
		for (i = 0; i < Prefadoros.feredata.dedomena.l.length; i++) {
			Skiniko.isProsklisi(Prefadoros.feredata.dedomena.l[i].k).prosklisiAddDOM();
		}

		Prosklisi.zebra();
	}

	if (Prefadoros.ego.sinedria.isTheatis()) Prefadoros.ego.trapezi.trapeziBoxJQL().addClass('trapeziTheatis');
	Prefadoros.optiki.init();

	Prefadoros.ego.miaPrefaFixDOM();
	Prefadoros.ego.fixDOM();

	// Τα σκηνικά δεδομένα έχουν ανακλαστεί στο DOM και έχουμε πλέον στη
	// σελίδα του browser την πλήρη εικόνα του καφενείου.

	$('#loginPhotoContainer').find('.loginAxiomaIcon').remove();
	if (Prefadoros.ego.pektis.axioma()) $('#loginPhotoContainer').
		prepend($('<img>').addClass('loginAxiomaIcon').axiomaIconFixDOM(Prefadoros.ego.pektis));

	// Ήρθε η ώρα να δούμε αν πρόκειται για το δικό μας τραπέζι και να
	// προβούμε σε περαιτέρω ενέργειες.

	if (Prefadoros.ego.oxiTrapezi()) return;

	// Πρόκειται για το δικό μας τραπέζι. Θα διαβάσουμε (και ταυτόχρονα θα εμφανίσουμε)
	// τη συζήτηση τού τραπεζιού, και κατόπιν θα διαβάσουμε τις ενέργειες τις τελευταίας
	// διανομής.

	Prefadoros.ego.trapezi.
	sizitisiSet(Prefadoros.feredata.dedomena['Z']).
	energiaSet(Prefadoros.feredata.dedomena['E']);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η μέθοδος "feredataSet" δέχεται δεδομένα τραπεζιού σε feredata format και
// αναθέτει αυτά τα δεδομένα στα αντίστοιχα properties του τραπεζιού.

Trapezi.prototype.feredataSet = function(data) {
	var thesi, l, s, param, marap, i;

	// Όλα τα properties τού τραπεζιού επανατίθενται με βάση
	// την πληροφορία μεταφέρει η παράμετρος "data".

	this.kodikos = data[Prefadoros.trapeziEco('kodikos')];
	this.stisimo = data[Prefadoros.trapeziEco('stisimo')];
	for (thesi in Prefadoros.thesiValid) {
		l = 'pektis' + thesi;
		s = Prefadoros.trapeziEco(l);
		this[l] = data.hasOwnProperty(s) ? data[s] : null;
		l = 'apodoxi' + thesi;
		s = Prefadoros.trapeziEco(l);
		this[l] = data.hasOwnProperty(s) ? data[s] : 1;
	}

	if (data.hasOwnProperty('r')) {
		for (param in data.r) {
			marap = Prefadoros.trparamOce(param);
			this.trparamSet(marap, Prefadoros.trparamDecode(marap, data.r[param]));
		}
	}

	if (data.hasOwnProperty('d')) {
		for (i = 0; i < data.d.length; i++) {
			this.dianomiAdd(new Dianomi().feredataSet(data.d[i]));
		}
	}

	return this;
}

Dianomi.prototype.feredataSet = function(data) {
	var i;

	for (i in data) {
		this[Prefadoros.dianomiOce(i)] = parseInt(data[i]);
	}

	return this;
}

Energia.prototype.feredataSet = function(data) {
	this['pektis'] = parseInt(data[Prefadoros.energiaEco('pektis')]);
	this['idos'] = Prefadoros.energiaIdosOce(data[Prefadoros.energiaEco('idos')]);
	this['pote'] = parseInt(data[Prefadoros.energiaEco('pote')]);
	this['data'] = data[Prefadoros.energiaEco('data')];
	return this;
}

// Η μέθοδος "feredataSet" δέχεται δεδομένα συνεδρίας σε feredata format,
// αναθέτει τις τιμές των δεδομένων αυτών στα αντίστοιχα properties τής
// συνεδρίας και επιστρέφει την συνεδρία.

Sinedria.prototype.feredataSet = function(data) {
	var tprop;

	// Όλα τα properties τής συνεδρίας επανατίθενται με βάση
	// την πληροφορία μεταφέρει η παράμετρος "data".

	this.pektis = data[Prefadoros.sinedriaEco('pektis')];
	this.ip = data[Prefadoros.sinedriaEco('ip')];
	this.isodos = data[Prefadoros.sinedriaEco('isodos')];
	this.used = globals.toraServer();

	// Τυχόν στοιχεία θέσης στα δεδομένα τίθενται με χρήση τής
	// αρμοδίας μεθόδου προς αποφυγήν αντιφατικών καταστάσεων.

	tprop = Prefadoros.sinedriaEco('trapezi');
	if (data.hasOwnProperty(tprop)) return this.trapeziSet(data[tprop],
		data[Prefadoros.sinedriaEco('thesi')], data[Prefadoros.sinedriaEco('theatis')]);

	return this.trapeziSet();

}

// Η μέθοδος "feredataSet" δέχεται δεδομένα παίκτη σε feredata format,
// αναθέτει τις τιμές των δεδομένων αυτών στα αντίστοιχα properties τού
// παίκτη και επιστρέφει τον παίκτη.

Pektis.prototype.feredataSet = function(login, data) {
	var param, marap;

	// Όλα τα properties τού παίκτη επανατίθενται με βάση
	// την πληροφορία μεταφέρει η παράμετρος "data".

	this.login = login;
	this.onoma = data.o;
	for (param in data.r) {
		marap = Prefadoros.peparamOce(param);
		this.peparamSet(marap, Prefadoros.peparamDecode(marap, data.r[param]));
	}

	return this;
}

// Η μέθοδος "feredataSet" δέχεται δεδομένα πρόσκλησης σε feredata format,
// αναθέτει τις τιμές των δεδομένων αυτών στα αντίστοιχα properties τής
// πρόσκλησης και επιστρέφει την πρόσκληση.

Prosklisi.prototype.feredataSet = function(data) {
	var trapezi;

	if (!data.hasOwnProperty('k')) globals.fatal('Prosklisi.feredataSet: ακαθόριστος κωδικός');
	if (isNaN(data.k) || (data.k != parseInt(data.k)) ||
		(data.k <= 0)) globals.fatal('Prosklisi.feredataSet: ' + data.k + ': απαράδεκτος κωδικός');
	if (!data.hasOwnProperty('t')) globals.fatal('Prosklisi.feredataSet: ακαθόριστο τραπέζι');
	if (!data.hasOwnProperty('a')) data.a = Prefadoros.ego.login;
	if (!data.hasOwnProperty('p')) data.p = data.a;
	if (!data.hasOwnProperty('e')) data.e = globals.toraServer();

	trapezi = Skiniko.isTrapezi(data.t);
	if (!trapezi) globals.fatal('Prosklisi.feredataSet: ' + data.t + ': δεν βρέθηκε το τραπέζι');

	this.kodikos = parseInt(data.k);
	this.trapezi = trapezi.kodikos;
	this.apo = data.a;
	this.pros = data.p;
	this.epidosi = parseInt(data.e);
	return this;
}

// Η μέθοδος "kinisiSet" δέχεται δεδομένα κίνησης νέας συνεδρίας και
// αναθέτει τις τιμές των δεδομένων αυτών στα αντίστοιχα properties
// τής συνεδρίας, αλλά και τού αντίστοιχου παίκτη. Αν ο παίκτης δεν
// βρεθεί στο σκηνικό εισάγεται.

Sinedria.prototype.kinisiSet = function(data) {
	var pektis, param, marap;

	this.pektis = globals.fetchProp(data, 'p');
	this.ip = data['i'];
	this.isodos = globals.toraServer();

	pektis = Skiniko.isPektis(this.pektis);
	if (!pektis) pektis = (new Pektis(this['pektis'])).pektisAdd();
	pektis.onoma = data['o'];

	for (param in data.r) {
		marap = Prefadoros.peparamOce(param);
		pektis.peparamSet(marap, Prefadoros.peparamDecode(marap, data.r[param]));
	}

	return this;
}

// Η μέθοδος "feredataSet" δέχεται το login name κάποιου παίκτη και το
// εσωτερικό είδος τής σχέσης τού παίκτη που τρέχει το πρόγραμμα με τον
// εν λόγω παίκτη, θέτει ανάλογα τα στοιχεία της σχέσης, και επιστρέφει
// την σχέση.

Sxesi.prototype.feredataSet = function(sxetizomenos, sxesi) {
	this.pektis = Prefadoros.ego.login;
	this.sxetizomenos = sxetizomenos;
	this.sxesi = sxesi;
	return this;
}

Sizitisi.prototype.feredataSet = function(sxolio) {
	this.pektis = sxolio.p;
	this.kimeno = sxolio.k;
	this.pote = sxolio.w;
	return this;
}

// Η μέθοδος "kinisiSet" δέχεται ένα αντικείμενο κίνησης σχέσης ("SX"),
// θέτει ανάλογα τα properties της ανά χείρας σχέσης, και επιστρέφει
// τη σχέση. Ασχέτως αν έχει μεταφερθεί property οικοδεσπότη ("p"),
// οικοδεσπότης πρέπει να είναι πάντα ο τρέχων παίκτης, καθώς είναι
// ο μόνος ο οποίος δικαιούται να λάβει τέτοια πληροφορία.

Sxesi.prototype.kinisiSet = function(kinisi) {
	this.pektis = Prefadoros.ego.login;
	this.sxetizomenos = globals.fetchProp(kinisi, 'l');
	if (kinisi.hasOwnProperty('x')) this.sxesi = kinisi.x;
	else delete this.sxesi;
	return this;
}

Prosklisi.prototype.kinisiSet = function(kinisi) {
	this.kodikos = parseInt(kinisi.fetchProp('k'));
	this.trapezi = parseInt(kinisi.fetchProp('t'));
	this.apo = kinisi.fetchProp('a');
	this.pros = kinisi.hasOwnProperty('p') ? kinisi.p : kinisi.a;
	this.epidosi = kinisi.hasOwnProperty('e') ? parseInt(kinisi.e) : globals.toraServer();
	return this;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η function "metenergia" είναι αυτή που θα εμφανίσει στο τραπέζι διάφορες χρήσιμες
// πληροφορίες και θα μεριμνήσει για την υποδοχή των επιλογών τού παίκτη, π.χ. δήλωση,
// ξεσκαρτάρισμα, παίξιμο κλπ.

Prefadoros.feredata.metenergia = function() {
	var trapezi = Prefadoros.ego.isTrapezi();

	// Ακυρώνουμε τυχόν ενδείξεις σειράς ενεργειών για τους παίκτες.

	$('#PXdealer').remove();
	$('#PXprotos').remove();
	$('.epomenos').removeClass('epomenos');
	Prefadoros.epomenos.ipenthimisiClear();
	$('.pektisAnamoniIcon').remove();

	// Καθαρίζουμε τις περιοχές μηνυμάτων που αφορούν στις ενέργειες
	// των παικτών.

	Client.fyi.kato();
	Prefadoros.tsoxa.fyi();

	// Ακυρώνουμε τυχόν panel επιλογής επόμενης ενέργειας και mouse event
	// listeners για τα φύλλα.

	$('#PXpanel').remove();
	$('.filoIcon').off('click mouseenter mouseleave');

	// Αν ο χρήστης δεν βρίσκεται σε κάποιο τραπέζι, δεν χρειάζεται να γίνουν
	// περαιτέρω ενέργειες.

	if (!trapezi) return;

	// Ο χρήστης βρίσκεται σε κάποιο τραπέζι και εμφανίζουμε όλες τις απαραίτητες
	// πληροφορίες που αφορούν στη σειρά των παικτών, π.χ. dealer, πρώτος, επόμενος
	// κλπ.

	trapezi.
	siraDOM().

	// Ακολουθεί μέθοδος διαμόρφωσης του γηπέδου ανάλογα με τη φάση στην οποία
	// βρίσκεται το τραπέζι.

	gipedoDOM().

	// Ακολουθεί μέθοδος εκτύπωσης μηνυμάτων ενημέρωσης παικτών και θεατών σχετικά
	// με τη φάση και την εξέλιξη του παιχνιδιού.

	minimaDOM().

	// Ακολουθούν διεργασίες σχετικές με την εκάστοτε φάση του τραπεζιού. Αυτές οι
	// διεργασίες αφορούν σε όλους τους παίκτες και θεατές που σχετίζονται με το
	// τραπέζι.

	fasiDOM();
}
